#include "GfxD3D9.h"
#include <Config.h>

namespace imGraphics {	
	LPDIRECT3DDEVICE9 g_DeviceD3D9;
	LPDIRECT3DVERTEXDECLARATION9 VertexDecl;

	D3DXMATRIX *g_World, *g_View, *g_Projection, *g_VP;
}

using namespace imGraphics;

D3D9Renderer::D3D9Renderer() {
	pD3D = NULL;
	pd3dDevice = NULL;
	m_WndHandle = NULL;

	m_FOV = acos(-1.0f)/4.0f;
	m_NearZ = 1.0f;
	m_FarZ = 1000.0f;

	SetRes(1024, 768);
	SetMode(DSP_WINDOW);
	SetVSync(true);

	imGraphics::g_World = &m_D3DWorld;
	imGraphics::g_View = &m_D3DView;
	imGraphics::g_Projection = &m_D3DProjection;
	imGraphics::g_VP = &m_D3DVP;
}

D3D9Renderer::~D3D9Renderer() {
	Release();
}

void D3D9Renderer::SetupFromFile(Config* Cfg) {
	int w = Cfg->GetInt("r_width", 1024);
	int h = Cfg->GetInt("r_height", 768);
	SetRes(w, h);
	SetMode((DisplayMode)Cfg->GetInt("r_displaymode", 1));
	SetVSync(Cfg->GetBool("r_vsync", true));
}

void D3D9Renderer::Init(HINSTANCE Instance, HWND Wnd) {
	m_WndHandle = Wnd;
	m_hInstance = Instance;

	Init();
}

void D3D9Renderer::Init() {
	if(m_WndHandle == NULL || m_hInstance == NULL)
		return;

	if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return; // Failed

	D3DFORMAT BackBufferFormat;
	bool Windowed;

	switch(m_Disp) {
	case DSP_WINDOW:
	case DSP_WINDOWNOBORDER:
		BackBufferFormat = D3DFMT_UNKNOWN;
		Windowed = TRUE;
		break;
	case DSP_FULLSCREEN:
		BackBufferFormat = D3DFMT_X8R8G8B8;
		Windowed = FALSE;
		break;
	};

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.PresentationInterval = m_DisplayInterval;
	d3dpp.Windowed = Windowed;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = BackBufferFormat; //BackBufferFormat;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferWidth = m_w;
	d3dpp.BackBufferHeight = m_h;
	d3dpp.hDeviceWindow = m_WndHandle;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,
								 D3DDEVTYPE_HAL,
								 m_WndHandle,
								 D3DCREATE_HARDWARE_VERTEXPROCESSING,
								 &d3dpp,
								 &pd3dDevice ) ) )
		return; // Failed

	imGraphics::g_DeviceD3D9 = pd3dDevice;

	pd3dDevice->CreateVertexDeclaration(declVertex, &VertexDecl);
	pd3dDevice->SetVertexDeclaration(VertexDecl);

	HRESULT hr = S_OK;

	//pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
	//pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
	//pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
	//pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
}

void D3D9Renderer::Release() {
	if(pD3D != NULL) {
		pD3D->Release();
		pD3D = NULL;
	}
	if(pd3dDevice != NULL) {
		pd3dDevice->Release();
		pd3dDevice = NULL;
	}
}

void D3D9Renderer::Cleanup() {
	Release();
}

void D3D9Renderer::SetRes(unsigned int w, unsigned int h) {
	if(w != 0)
		m_w = w;
	if(h != 0)
		m_h = h;

	m_Aspect = m_w/(float)m_h;

	SetProjectionMatrix(Matrix::Projection3D(m_NearZ, m_FarZ, m_FOV, m_Aspect));
}

void D3D9Renderer::SetMode(DisplayMode dMode) {
	m_Disp = dMode;
}

void D3D9Renderer::SetVSync(bool bVsync) {
	if(bVsync)
		m_DisplayInterval = D3DPRESENT_INTERVAL_ONE;
	else
		m_DisplayInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
}